unit uniExplosions;

interface

uses
  gl,
  Classes;

type

  ExploType =
    (
    EnemyDestroyed,
    EnemyDamage,
    EnemyAmmo00,
    EnemyAmmo01,
    EnemyAmmo02,
    EnemyAmmo03,
    EnemyAmmo04,
    HeroDestroyed,
    HeroDamage,
    HeroAmmo00,
    HeroAmmo01,
    HeroAmmo02,
    HeroShields,
    PowerBurst,
    AddLife,
    LoseLife,
    ScoreLife,
    Electric,
    Glitter,
    NumExploTypes
    );

  { Explo }

  Explo = class(TObject)
  public
    pos: array[0..2] of Single;
    vel: array[0..2] of Single;
    clr: array[0..3] of Single;

    age: Integer;
    size: Single;

    back: Explo;
    next: Explo;


    constructor Create;
    destructor Destroy; override;

    procedure init(p: array of Single; a: Integer = 0; s: Single = 1.0); overload;
    procedure init(p, v, c: array of Single; a: Integer = 0; s: Single = 1.0); overload;
  end;


  { Explosions }

  Explosions = class(TObject)
  public
    exploRoot: array[0..Integer(NumExploTypes) - 1] of Explo;
    exploPool: Explo;
    tex: array[0..Integer(NumExploTypes) - 1] of GLuint;
    exploSize: array[0..Integer(NumExploTypes) - 1, 0..1] of Single;
    exploStay: array[0..Integer(NumExploTypes) - 1] of Single;
    exploPause: array[0..Integer(NumExploTypes) - 1, 0..2] of Single; //  frames to not allow explosions. [0] = count, [1] = base, [2] = flag

    //game: Global;

    constructor Create;
    destructor Destroy; override;

    function addExplo(t: ExploType; p: array of Single; age: Integer = 0; size: Single = 1.0): Explo;
    function addElectric(p, v, clr: array of Single; age: Integer = 0; size: Single = 1.0): Explo;
    function addGlitter(p, v, clr: array of Single; age: Integer = 0; size: Single = 1.0): Explo;

    procedure update;
    procedure drawGL;
    procedure clear;

    procedure loadTextures;
    procedure deleteTextures;

    procedure drawExplo(temp: ExploType);
    procedure drawAmmo(temp: ExploType);
    procedure drawBurst(temp: ExploType);
    procedure drawShields(temp: ExploType);
    procedure drawLife(temp: ExploType);
    procedure drawElectric(temp: ExploType);
    procedure drawGlitter(temp: ExploType);

    function getNewExplo: Explo;
    procedure killExplo(dead: Explo);

  end;

var
  exploCount: Integer = 0;


implementation

uses
  PNGLoader,
  uniDefine,
  uniGlobal;

{ Explosions }

function Explosions.addElectric(p, v, clr: array of Single; age: Integer; size: Single): Explo;
var
  newExplo: Explo;
  first: Explo;
begin
  newExplo := nil;
  first := nil;

  exploPause[Integer(Electric), 2] := 1; //-- set flag to init explo pause count
  newExplo := getNewExplo;
  newExplo.init(p, v, clr, age, size);
  newExplo.back := exploRoot[Integer(Electric)];
  newExplo.next := exploRoot[Integer(Electric)].next;
  first := exploRoot[Integer(Electric)].next;
  if Boolean(first) then first.back := newExplo;
  exploRoot[Integer(Electric)].next := newExplo;
  Result := newExplo;
end;

function Explosions.addExplo(t: ExploType; p: array of Single; age: Integer; size: Single): Explo;
var
  newExplo: Explo;
  first: Explo;
begin
  newExplo := nil;
  first := nil;

  if exploPause[Integer(t)][0] <= 0 then
  begin
    exploPause[Integer(t)][2] := 1; //-- set flag to init explo pause count
    newExplo := getNewExplo;
    newExplo.init(p, age, size);
    newExplo.back := exploRoot[Integer(t)];
    newExplo.next := exploRoot[Integer(t)].next;
    first := exploRoot[Integer(t)].next;
    if Boolean(first) then
      first.back := newExplo;
    exploRoot[Integer(t)].next := newExplo;
  end;

  Result := newExplo;
end;

function Explosions.addGlitter(p, v, clr: array of Single; age: Integer; size: Single): Explo;
var
  newExplo: Explo;
  first: Explo;
begin
  newExplo := nil;
  first := nil;

  exploPause[Integer(Glitter)][2] := 1; //-- set flag to init explo pause count
  newExplo := getNewExplo;
  newExplo.init(p, v, clr, age, size);
  newExplo.back := exploRoot[Integer(Glitter)];
  newExplo.next := exploRoot[Integer(Glitter)].next;
  first := exploRoot[Integer(Glitter)].next;
  if Boolean(first) then first.back := newExplo;
  exploRoot[Integer(Glitter)].next := newExplo;

  Result := newExplo;
end;

procedure Explosions.clear;
var
  i: Integer;
  cur: Explo;
  del: Explo;
begin
  for i := 0 to Integer(NumExploTypes) - 1 do
  begin
    cur := exploRoot[i].next;
    while Boolean(cur) do
    begin
      del := cur;
      cur := cur.next;
      killExplo(del);
    end;
    exploRoot[i].next := nil;
  end;
end;

constructor Explosions.Create;
var
  i: Integer;
begin
  //game = Global::getInstance();
  for i := 0 to Integer(NumExploTypes) - 1 do
  begin
    tex[i] := 0;
    exploRoot[i] := Explo.Create;
    exploSize[i][0] := 0.5;
    exploSize[i][1] := 0.5;
    exploStay[i] := 20.0;
    exploPause[i][0] := 0;
    exploPause[i][1] := 0;
    exploPause[i][2] := 0;
  end;

  exploPool := Explo.Create;

  loadTextures;
  exploSize[Integer(EnemyDestroyed)][0] := 1.35;
  exploSize[Integer(EnemyDestroyed)][1] := 1.35;
  exploStay[Integer(EnemyDestroyed)] := 30.0;

  exploSize[Integer(EnemyDamage)][0] := 1.0;
  exploSize[Integer(EnemyDamage)][1] := 1.0;
  exploStay[Integer(EnemyDamage)] := 20.0;
  exploPause[Integer(EnemyDamage)][1] := 3;

  exploSize[Integer(EnemyAmmo00)][0] := 1.5;
  exploSize[Integer(EnemyAmmo00)][1] := 1.5;
  exploStay[Integer(EnemyAmmo00)] := 15.0;
  exploPause[Integer(EnemyAmmo00)][1] := 1;

  exploSize[Integer(EnemyAmmo01)][0] := 0.5;
  exploSize[Integer(EnemyAmmo01)][1] := 0.5;
  exploStay[Integer(EnemyAmmo01)] := 10.0;
  exploPause[Integer(EnemyAmmo01)][1] := 3;

  exploSize[Integer(EnemyAmmo02)][0] := 1.7;
  exploSize[Integer(EnemyAmmo02)][1] := 1.7;
  exploStay[Integer(EnemyAmmo02)] := 10.0;
  exploPause[Integer(EnemyAmmo02)][1] := 2;

  exploSize[Integer(EnemyAmmo03)][0] := 1.7;
  exploSize[Integer(EnemyAmmo03)][1] := 1.7;
  exploStay[Integer(EnemyAmmo03)] := 10.0;
  exploPause[Integer(EnemyAmmo03)][1] := 2;

  exploSize[Integer(EnemyAmmo04)][0] := 2.0;
  exploSize[Integer(EnemyAmmo04)][1] := 1.5;
  exploStay[Integer(EnemyAmmo04)] := 10.0;
  exploPause[Integer(EnemyAmmo04)][1] := 5;

  exploSize[Integer(HeroDestroyed)][0] := 1.5;
  exploSize[Integer(HeroDestroyed)][1] := 1.5;
  exploStay[Integer(HeroDestroyed)] := 25.0;

  exploSize[Integer(HeroDamage)][0] := 1.1;
  exploSize[Integer(HeroDamage)][1] := 1.1;
  exploStay[Integer(HeroDamage)] := 25.0;
  exploPause[Integer(HeroDamage)][1] := 3;

  exploSize[Integer(HeroAmmo00)][0] := 0.25;
  exploSize[Integer(HeroAmmo00)][1] := 0.25;
  exploStay[Integer(HeroAmmo00)] := 10.0;

  exploSize[Integer(HeroAmmo01)][0] := 0.5;
  exploSize[Integer(HeroAmmo01)][1] := 1.0;
  exploStay[Integer(HeroAmmo01)] := 15.0;
  exploPause[Integer(HeroAmmo01)][1] := 1;

  exploSize[Integer(HeroAmmo02)][0] := 0.9;
  exploSize[Integer(HeroAmmo02)][1] := 1.0;
  exploStay[Integer(HeroAmmo02)] := 23.0;

  exploSize[Integer(HeroShields)][0] := 1.6;
  exploSize[Integer(HeroShields)][1] := 1.6;
  exploStay[Integer(HeroShields)] := 25.0;
  exploPause[Integer(HeroShields)][1] := 5;

  exploSize[Integer(PowerBurst)][0] := 1.8;
  exploSize[Integer(PowerBurst)][1] := 1.8;
  exploStay[Integer(PowerBurst)] := 35.0;

  exploSize[Integer(AddLife)][0] := 2.5;
  exploSize[Integer(AddLife)][1] := 2.5;
  exploStay[Integer(AddLife)] := 25.0;

  exploSize[Integer(LoseLife)][0] := 3.5;
  exploSize[Integer(LoseLife)][1] := 3.5;
  exploStay[Integer(LoseLife)] := 35.0;

  exploSize[Integer(ScoreLife)][0] := 3.5;
  exploSize[Integer(ScoreLife)][1] := 3.5;
  exploStay[Integer(ScoreLife)] := 35.0;

  exploSize[Integer(Electric)][0] := 1.7;
  exploSize[Integer(Electric)][1] := 0.5;
  exploStay[Integer(Electric)] := 43.0;
  exploPause[Integer(Electric)][1] := 0;

  exploSize[Integer(Glitter)][0] := 0.8;
  exploSize[Integer(Glitter)][1] := 1.0;
  exploStay[Integer(Glitter)] := 20.0;
  exploPause[Integer(Glitter)][1] := 0;
end;

procedure Explosions.deleteTextures;
var
  i: Integer;
begin
  for i := 0 to Integer(NumExploTypes) - 1 do
  begin
    glDeleteTextures(1, @tex[i]);
    tex[i] := 0;
  end;
end;

destructor Explosions.Destroy;
var
  cur: Explo;
  del: Explo;
  i: Integer;
begin
  //inherited;
  clear; //-- move all explosions into the pool

  cur := exploPool.next;
  while Boolean(cur) do
  begin
    del := cur;
    cur := cur.next;
    del.Destroy;
  end;

  for i := 0 to Integer(NumExploTypes) - 1 do
  begin
    exploRoot[i].Destroy;
  end;
  exploPool.Destroy;

  deleteTextures;
end;

procedure Explosions.drawAmmo(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  clr: Single;
  pos: array of Single;
  thisExplo: Explo;
begin
  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  glBegin(GL_QUADS);
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    ex := exploSize[Integer(temp)][0] * ((age + 5.0) / (exploStay[Integer(temp)] + 5.0));
    ey := exploSize[Integer(temp)][1] * ((age + 5.0) / (exploStay[Integer(temp)] + 5.0));
    clr := age / exploStay[Integer(temp)];
    //tmp := clr*clr*clr;
    clr := (1.2 - clr);
    if clr > 1.0 then clr := 1.0;
    glColor4f(1.0, 1.0, 1.0, clr);
    pos := @thisExplo.pos;
    glTexCoord2f(0.0, 0.0); glVertex3f(pos[0] - ex, pos[1] + ey, pos[2]);
    glTexCoord2f(0.0, 1.0); glVertex3f(pos[0] - ex, pos[1] - ey, pos[2]);
    glTexCoord2f(1.0, 1.0); glVertex3f(pos[0] + ex, pos[1] - ey, pos[2]);
    glTexCoord2f(1.0, 0.0); glVertex3f(pos[0] + ex, pos[1] + ey, pos[2]);
    thisExplo := thisExplo.next; //ADVANCE
  end;
  glEnd;
end;

procedure Explosions.drawBurst(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  clr, tmp: Single;
  pos: array of Single;
  thisExplo: Explo;
begin
  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    tmp := 1.0 * age / exploStay[Integer(temp)];
    clr := tmp;
    ex := thisExplo.size * exploSize[Integer(temp)][0] * clr;
    ey := thisExplo.size * exploSize[Integer(temp)][1] * clr;
    clr := tmp * 0.75;
    glColor4f(clr + 0.5, clr + 0.2, clr + 0.1, clr);
    pos := @thisExplo.pos;
    glPushMatrix;
    glTranslatef(pos[0], pos[1], pos[2]);
    glRotatef(IRAND, 0.0, 0.0, 1.0);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-ex, ey, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-ex, -ey, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(ex, -ey, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(ex, ey, 0.0);
    glEnd;
    glRotatef(IRAND, 0.0, 0.0, 1.0);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-ex, ey, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-ex, -ey, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(ex, -ey, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(ex, ey, 0.0);
    glEnd;
    glPopMatrix;
    thisExplo := thisExplo.next; //ADVANCE
  end;
end;

procedure Explosions.drawElectric(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  alpha, tmp: Single;
  clr: array of Single;
  pos: array of Single;
  thisExplo: Explo;
  tOff: Single;
begin
  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    if age >= 0 then
    begin
      tmp := age / exploStay[Integer(temp)];
      alpha := 1.0 - tmp;
      alpha := 5.0 * (alpha * alpha);
      clr := @thisExplo.clr;
      glColor4f(clr[0], clr[1], clr[2], clr[3] * alpha);
      ex := exploSize[Integer(temp)][0];
      ey := exploSize[Integer(temp)][1] * tmp;
      tmp := (1.0 - uniGlobal.speedAdj) + (uniGlobal.speedAdj * 1.075);
      thisExplo.vel[0] := thisExplo.vel[0] * tmp;
      thisExplo.vel[1] := thisExplo.vel[1] * tmp;
      thisExplo.vel[2] := thisExplo.vel[2] * tmp;
      pos := @thisExplo.pos;
      tOff := FRAND;
      glPushMatrix;
      glTranslatef(pos[0], pos[1], pos[2]);
      glBegin(GL_QUADS);
      glTexCoord2f(0.0, 0.0 + tOff); glVertex3f(-ex, ey, 0.0);
      glTexCoord2f(0.0, 0.2 + tOff); glVertex3f(-ex, -ey, 0.0);
      glTexCoord2f(1.0, 0.2 + tOff); glVertex3f(ex, -ey, 0.0);
      glTexCoord2f(1.0, 0.0 + tOff); glVertex3f(ex, ey, 0.0);
      glEnd;
      glPopMatrix;
    end;
    thisExplo := thisExplo.next; //ADVANCE
  end;
end;

procedure Explosions.drawExplo(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  exs, eys: Single;
  p: array of Single;
  clr, tmp: Single;
  xoff, yoff: Single;
  thisExplo: Explo;
begin
  glColor4f(1.0, 1.0, 1.0, 1.0);

  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  glBegin(GL_QUADS);
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    if age >= 0 then
    begin
      clr := age / exploStay[Integer(temp)];
      ex := thisExplo.size * exploSize[Integer(temp)][0] * clr;
      ey := thisExplo.size * exploSize[Integer(temp)][1] * clr;
      exs := ex * 0.7;
      eys := ey * 0.7;
      tmp := clr * clr;
      clr := 1.2 - clr;
      tmp := 0.5 + clr * 0.5;
      glColor4f(tmp, tmp, tmp, clr);

      if temp = HeroDamage then
        p := @uniGlobal._hero.pos
      else
        p := @thisExplo.pos;

      if temp = EnemyDestroyed then
      begin
        xoff := 0.1;
        yoff := 0.3;
        glTexCoord2f(0.0, 1.0); glVertex3f(p[0] - exs + xoff, p[1] + eys + yoff, p[2]);
        glTexCoord2f(0.0, 0.0); glVertex3f(p[0] - exs + xoff, p[1] - eys + yoff, p[2]);
        glTexCoord2f(1.0, 0.0); glVertex3f(p[0] + exs + xoff, p[1] - eys + yoff, p[2]);
        glTexCoord2f(1.0, 1.0); glVertex3f(p[0] + exs + xoff, p[1] + eys + yoff, p[2]);

        xoff := -0.2;
        yoff := -0.4;
        glTexCoord2f(0.0, 1.0); glVertex3f(p[0] - exs + xoff, p[1] + eys + yoff, p[2]);
        glTexCoord2f(0.0, 0.0); glVertex3f(p[0] - exs + xoff, p[1] - eys + yoff, p[2]);
        glTexCoord2f(1.0, 0.0); glVertex3f(p[0] + exs + xoff, p[1] - eys + yoff, p[2]);
        glTexCoord2f(1.0, 1.0); glVertex3f(p[0] + exs + xoff, p[1] + eys + yoff, p[2]);
      end;
      xoff := 0.0;
      yoff := -0.3;
      glTexCoord2f(0.0, 1.0); glVertex3f(p[0] - ex + xoff, p[1] + ey + yoff, p[2]);
      glTexCoord2f(0.0, 0.0); glVertex3f(p[0] - ex + xoff, p[1] - ey + yoff, p[2]);
      glTexCoord2f(1.0, 0.0); glVertex3f(p[0] + ex + xoff, p[1] - ey + yoff, p[2]);
      glTexCoord2f(1.0, 1.0); glVertex3f(p[0] + ex + xoff, p[1] + ey + yoff, p[2]);
    end;

    thisExplo := thisExplo.next; //ADVANCE
  end;
end;

procedure Explosions.drawGL;
begin
  if Boolean(exploRoot[Integer(EnemyDestroyed)].next) then drawExplo(EnemyDestroyed);
  if Boolean(exploRoot[Integer(EnemyDamage)].next) then drawExplo(EnemyDamage);
  if Boolean(exploRoot[Integer(EnemyAmmo00)].next) then drawAmmo(EnemyAmmo00);
  if Boolean(exploRoot[Integer(EnemyAmmo01)].next) then drawAmmo(EnemyAmmo01);
  if Boolean(exploRoot[Integer(EnemyAmmo02)].next) then drawAmmo(EnemyAmmo02);
  if Boolean(exploRoot[Integer(EnemyAmmo03)].next) then drawAmmo(EnemyAmmo03);
  if Boolean(exploRoot[Integer(EnemyAmmo04)].next) then drawAmmo(EnemyAmmo04);

  if Boolean(exploRoot[Integer(HeroDestroyed)].next) then drawExplo(HeroDestroyed);
  if Boolean(exploRoot[Integer(HeroDamage)].next) then drawExplo(HeroDamage);
  if Boolean(exploRoot[Integer(HeroAmmo00)].next) then drawAmmo(HeroAmmo00);
  if Boolean(exploRoot[Integer(HeroAmmo01)].next) then drawAmmo(HeroAmmo01);
  if Boolean(exploRoot[Integer(HeroAmmo02)].next) then drawAmmo(HeroAmmo02);

  if Boolean(exploRoot[Integer(HeroShields)].next) then drawShields(HeroShields);
  if Boolean(exploRoot[Integer(PowerBurst)].next) then drawBurst(PowerBurst);

  if Boolean(exploRoot[Integer(AddLife)].next) then drawLife(AddLife);
  if Boolean(exploRoot[Integer(LoseLife)].next) then drawLife(LoseLife);
  if Boolean(exploRoot[Integer(ScoreLife)].next) then drawLife(ScoreLife);

  if Boolean(exploRoot[Integer(Electric)].next) then drawElectric(Electric);
  if Boolean(exploRoot[Integer(Glitter)].next) then drawGlitter(Glitter);
end;

procedure Explosions.drawGlitter(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  alpha, tmp: Single;
  clr: array of Single;
  pos: array of Single;
  thisExplo: Explo;
begin
  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    if age >= 0 then
    begin
      tmp := age / exploStay[Integer(temp)];
      alpha := 1.0 - tmp;
      //alpha := 5.0*(alpha*alpha);
      clr := @thisExplo.clr;
      glColor4f(clr[0], clr[1], clr[2], clr[3] * alpha);
      tmp := alpha * alpha;
      ex := tmp * thisExplo.size * exploSize[Integer(temp)][0];
      ey := tmp * thisExplo.size * exploSize[Integer(temp)][1] + (0.02 * age);
      pos := @thisExplo.pos;
      glPushMatrix;
      glTranslatef(pos[0], pos[1], pos[2]);
      glBegin(GL_QUADS);
      glTexCoord2f(0.0, 0.0); glVertex3f(-ex, ey, 0.0);
      glTexCoord2f(0.0, 1.0); glVertex3f(-ex, -ey, 0.0);
      glTexCoord2f(1.0, 1.0); glVertex3f(ex, -ey, 0.0);
      glTexCoord2f(1.0, 0.0); glVertex3f(ex, ey, 0.0);
      glEnd;
      glPopMatrix;
    end;
    thisExplo := thisExplo.next; //ADVANCE
  end;
end;

procedure Explosions.drawLife(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  p: array of Single;
  clr: array[0..3] of Single;
  tmp: Single;
  thisExplo: Explo;
begin
  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  glBegin(GL_QUADS);
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    if age >= 0 then
    begin
      p := @thisExplo.pos;
      tmp := age / exploStay[Integer(temp)];
      if temp = AddLife then
      begin
        clr[0] := tmp;
        clr[1] := tmp;
        clr[2] := 1.0;
        clr[3] := tmp + 0.2;
        tmp := 1.0 - tmp;
      end
      else
      begin
        if temp = LoseLife then
        begin
          clr[0] := 1.0;
          clr[1] := 0.1;
          clr[2] := 0.1;
          clr[3] := 1.0 - tmp;
        end
        else
        begin
          clr[0] := 1.0;
          clr[1] := 1.0;
          clr[2] := 1.0;
          clr[3] := 1.0 - tmp;
        end;
      end;
      ex := thisExplo.size * exploSize[Integer(temp)][0] * tmp;
      ey := thisExplo.size * exploSize[Integer(temp)][1] * tmp;
      glColor4fv(@clr);
      glTexCoord2f(0.0, 1.0); glVertex3f(p[0] - ex, p[1] + ey, p[2]);
      glTexCoord2f(0.0, 0.0); glVertex3f(p[0] - ex, p[1] - ey, p[2]);
      glTexCoord2f(1.0, 0.0); glVertex3f(p[0] + ex, p[1] - ey, p[2]);
      glTexCoord2f(1.0, 1.0); glVertex3f(p[0] + ex, p[1] + ey, p[2]);
    end;
    thisExplo := thisExplo.next; //ADVANCE
  end;
  glEnd;
end;

procedure Explosions.drawShields(temp: ExploType);
var
  age: Single;
  ex, ey: Single;
  clr, tmp: Single;
  pos: array of Single;
  thisExplo: Explo;
begin
  if not uniGlobal._hero.isVisible then Exit;

  glBindTexture(GL_TEXTURE_2D, tex[Integer(temp)]);
  thisExplo := exploRoot[Integer(temp)].next;
  while Boolean(thisExplo) do
  begin
    age := thisExplo.age * uniGlobal.speedAdj;
    tmp := age / exploStay[Integer(temp)];
    clr := 1.0 - tmp;
    tmp := 0.5 + (clr * 0.5);
    ex := exploSize[Integer(temp)][0] * tmp;
    ey := exploSize[Integer(temp)][1] * tmp;
    glColor4f(clr, clr, 1.0, clr * 0.7);
    pos := @uniGlobal._hero.pos;
    glPushMatrix;
    glTranslatef(pos[0], pos[1], pos[2]);
    glRotatef(IRAND, 0.0, 0.0, 1.0);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-ex, ey, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-ex, -ey, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(ex, -ey, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(ex, ey, 0.0);
    glEnd;
    glPopMatrix;
    thisExplo := thisExplo.next; //ADVANCE
  end;
end;

function Explosions.getNewExplo: Explo;
var
  retExplo: Explo;
begin
  if Boolean(exploPool.next) then
  begin
    retExplo := exploPool.next;
    exploPool.next := retExplo.next;
  end
  else
  begin
    retExplo := Explo.Create;
  end;

  Result := retExplo;
end;

procedure Explosions.killExplo(dead: Explo);
begin
  dead.back := nil;
  dead.next := exploPool.next;
  exploPool.next := dead;
end;

procedure Explosions.loadTextures;
begin
  LoadTexture('png/enemyExplo.png', tex[Integer(EnemyDestroyed)]);
  tex[Integer(EnemyDamage)] := tex[Integer(EnemyDestroyed)];
  LoadTexture('png/enemyAmmoExplo00.png', tex[Integer(EnemyAmmo00)]);
  LoadTexture('png/enemyAmmoExplo01.png', tex[Integer(EnemyAmmo01)]);
  LoadTexture('png/enemyAmmoExplo02.png', tex[Integer(EnemyAmmo02)]);
  LoadTexture('png/enemyAmmoExplo03.png', tex[Integer(EnemyAmmo03)]);
  LoadTexture('png/enemyAmmoExplo04.png', tex[Integer(EnemyAmmo04)]);
  LoadTexture('png/enemyExplo.png', tex[Integer(HeroDestroyed)]);
  tex[Integer(HeroDamage)] := tex[Integer(HeroDestroyed)];
  LoadTexture('png/heroAmmoExplo00.png', tex[Integer(HeroAmmo00)]);
  LoadTexture('png/heroAmmoExplo01.png', tex[Integer(HeroAmmo01)]);
  LoadTexture('png/heroAmmoExplo02.png', tex[Integer(HeroAmmo02)]);
  LoadTexture('png/heroShields.png', tex[Integer(HeroShields)]);
  LoadTexture('png/powerUpTex.png', tex[Integer(PowerBurst)]);
  LoadTexture('png/life.png', tex[Integer(AddLife)]);
  tex[Integer(LoseLife)] := tex[Integer(AddLife)];
  tex[Integer(ScoreLife)] := tex[Integer(AddLife)];
  LoadTexture('png/electric.png', tex[Integer(Electric)]);
  LoadTexture('png/glitter.png', tex[Integer(Glitter)]);
end;

procedure Explosions.update;
var
  _explo: Explo;
  backExplo: Explo;
  nextExplo: Explo;
  i: Integer;
begin
  for i := 0 to Integer(NumExploTypes) - 1 do
  begin
    if (exploPause[i][0] > 0.0) then
      exploPause[i][0] := exploPause[i][0] - uniGlobal.speedAdj
    else
      exploPause[i][0] := 0.0;
    if Boolean(Round(exploPause[i][2])) then //-- if flag was set, init count
    begin
      exploPause[i][0] := exploPause[i][1];
      exploPause[i][2] := 0.0;
    end;
    _explo := exploRoot[i].next;
    while Boolean(explo) do
    begin
      Inc(_explo.age);
      if (_explo.age > 0) then
      begin
        _explo.pos[0] := _explo.pos[0] + _explo.vel[0] * uniGlobal.speedAdj;
        _explo.pos[1] := _explo.pos[1] + _explo.vel[1] * uniGlobal.speedAdj;
        _explo.pos[2] := _explo.pos[2] + _explo.vel[2] * uniGlobal.speedAdj;
      end;
      if (_explo.age > (exploStay[i] / uniGlobal.speedAdj)) then
      begin
        backExplo := _explo.back;
        nextExplo := _explo.next;
        backExplo.next := nextExplo;
        if Boolean(nextExplo) then
          nextExplo.back := backExplo;
        killExplo(_explo);
        _explo := nextExplo;
      end
      else
        _explo := _explo.next;
    end;
  end;
end;

{ Explo }

constructor Explo.Create;
begin
  age := 0;
  back := nil;
  next := nil;
  size := 1;
  Inc(exploCount);
end;

destructor Explo.Destroy;
begin
  Dec(exploCount);
  inherited;
end;

procedure Explo.init(p: array of Single; a: Integer; s: Single);
begin
  pos[0] := p[0];
  pos[1] := p[1];
  pos[2] := p[2];
  vel[0] := 0.0;
  vel[1] := 0.0;
  vel[2] := 0.0;
  clr[0] := 1.0;
  clr[1] := 1.0;
  clr[2] := 1.0;
  clr[3] := 1.0;
  age := Round(a / (uniGlobal.speedAdj));
  size := s;
  back := nil;
  next := nil;
end;

procedure Explo.init(p, v, c: array of Single; a: Integer; s: Single);
begin
  pos[0] := p[0];
  pos[1] := p[1];
  pos[2] := p[2];
  vel[0] := v[0];
  vel[1] := v[1];
  vel[2] := v[2];
  clr[0] := c[0];
  clr[1] := c[1];
  clr[2] := c[2];
  clr[3] := c[3];
  age := Round(a / (uniGlobal.speedAdj));
  size := s;
  back := nil;
  next := nil;
end;

end.

